package com.sec.android.app.myfiles.util;

import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Matrix;
import android.media.ExifInterface;

import com.sec.android.app.myfiles.info.AppConstants;
import com.sec.android.app.myfiles.log.Log;
import com.sec.android.app.myfiles.module.abstraction.FileRecord;

import java.io.IOException;

/**
 * Created by yunju.cha on 2017-04-17.
 */

public class ExifUtils {
    private static final String TAG = "ExifUtils";
    public static Bitmap createThumbnailFromEXIF(FileRecord record, int targetSize, int maxPixels) {
        String filePath = null;
        if (record != null && (record.getStorageType() == FileRecord.StorageType.Shortcut || record.getSize() > 0)) {
            filePath = record.getFullPath();
        }
        if (filePath == null) {
            return null;
        }

        byte[] thumbData = null;
        ExifInterface exif = getExif(filePath);
        if (exif != null) {
            thumbData = exif.getThumbnail();
        }

        BitmapFactory.Options fullOptions = new BitmapFactory.Options();
        BitmapFactory.Options exifOptions = new BitmapFactory.Options();
        int exifThumbWidth = 0;

        // Compute exifThumbWidth.
        if (thumbData != null) {
            exifOptions.inJustDecodeBounds = true;
            BitmapFactory.decodeByteArray(thumbData, 0, thumbData.length, exifOptions);
            exifOptions.inSampleSize = computeSampleSize(exifOptions, targetSize, maxPixels);
            exifThumbWidth = exifOptions.outWidth / exifOptions.inSampleSize;
        }

        // Compute fullThumbWidth.
        fullOptions.inJustDecodeBounds = true;
        BitmapFactory.decodeFile(filePath, fullOptions);
        fullOptions.inSampleSize = computeSampleSize(fullOptions, targetSize, maxPixels);
        int fullThumbWidth = fullOptions.outWidth / fullOptions.inSampleSize;

        // Choose the larger thumbnail as the returning sizedThumbBitmap.
        Bitmap sizedThumbBitmap;
        if (thumbData != null && (exifThumbWidth >= fullThumbWidth || record.getSize() > AppConstants.LARGE_IMAGE_SIZE)) {
            exifOptions.inJustDecodeBounds = false;
            sizedThumbBitmap = BitmapFactory.decodeByteArray(thumbData, 0, thumbData.length, exifOptions);
        } else {
            fullOptions.inJustDecodeBounds = false;
            sizedThumbBitmap = BitmapFactory.decodeFile(filePath, fullOptions);
        }

        if (exif != null) {
            int degree = getRotationAngleByExif(exif);
            if (degree != 0) {
                sizedThumbBitmap = getRotateBitmap(sizedThumbBitmap, degree);
            }
        }

        return sizedThumbBitmap;
    }

    private static int computeSampleSize(BitmapFactory.Options options, int minSideLength, int maxNumOfPixels) {
        int initialSize = computeInitialSampleSize(options, minSideLength, maxNumOfPixels);
        int roundedSize;
        if (initialSize <= 8) {
            roundedSize = 1;
            while (roundedSize < initialSize) {
                roundedSize <<= 1;
            }
        } else {
            roundedSize = (initialSize + 7) / 8 * 8;
        }
        return roundedSize;
    }

    private static int computeInitialSampleSize(BitmapFactory.Options options, int minSideLength, int maxNumOfPixels) {
        double w = options.outWidth;
        double h = options.outHeight;

        int lowerBound = (maxNumOfPixels == -1) ? 1 : (int) Math.ceil(Math.sqrt(w * h / maxNumOfPixels));
        int upperBound = (minSideLength == -1) ? 128 : (int) Math.min(Math.floor(w / minSideLength), Math.floor(h / minSideLength));

        if (upperBound < lowerBound) {
            // return the larger one when there is no overlapping zone.
            return lowerBound;
        }
        if (maxNumOfPixels == -1 && minSideLength == -1) {
            return 1;
        } else if (minSideLength == -1) {
            return lowerBound;
        } else {
            return upperBound;
        }
    }

    public static ExifInterface getExif(String filepath) {
        ExifInterface exif = null;
        try {
            exif = new ExifInterface(filepath);
        } catch (IOException e) {
            Log.e(TAG, "Exception:" + e.toString());
        } catch (NegativeArraySizeException e) {
            Log.e(TAG, "NegativeArraySizeException:" + e.toString());
        }
        return exif;
    }

    public static int getRotationAngleByExif(ExifInterface exif) {
        int nRet = 0;
        if (exif != null) {
            int orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, -1);
            if (orientation != -1) {
                // We only recognize a subset of orientation tag values.
                switch (orientation) {
                    case ExifInterface.ORIENTATION_ROTATE_90:
                        nRet = 90;
                        break;
                    case ExifInterface.ORIENTATION_ROTATE_180:
                        nRet = 180;
                        break;
                    case ExifInterface.ORIENTATION_ROTATE_270:
                        nRet = 270;
                        break;
                    default:
                        break;
                }
            }
        }
        return nRet;
    }

    public static Bitmap getRotateBitmap(Bitmap oriBmp, int degrees) {
        Bitmap retBmp = null;

        if (degrees != 0 && oriBmp != null) {
            Matrix m = new Matrix();
            m.setRotate(degrees, (float) oriBmp.getWidth() / 2, (float) oriBmp.getHeight() / 2);

            try {
                retBmp = Bitmap.createBitmap(oriBmp, 0, 0, oriBmp.getWidth(), oriBmp.getHeight(), m, true);
                if (retBmp != null && !oriBmp.isRecycled()) {
                    oriBmp.recycle();
                }
            } catch (OutOfMemoryError e) {
                // We have no memory to rotate. Return the original bitmap.
                Log.e(TAG, "OutOfMemoryError:" + e.toString());
            }
        }

        return retBmp;
    }
}
